package com.andy.blog.admin.service.impl;

import com.andy.blog.admin.dto.FileInfoDTO;
import com.andy.blog.admin.dto.SysRoleDTO;
import com.andy.blog.admin.dto.SysUserDTO;
import com.andy.blog.admin.service.FileBusService;
import com.andy.blog.admin.service.SysUserBusService;
import com.andy.blog.common.core.domain.entity.SysUser;
import com.andy.blog.common.core.domain.model.LoginUser;
import com.andy.blog.common.core.redis.RedisCache;
import com.andy.blog.common.exception.BlogServiceException;
import com.andy.blog.common.page.PageUtilsDTO;
import com.andy.blog.common.reponse.BlogResultCode;
import com.andy.blog.common.utils.SecurityUtils;
import com.andy.blog.common.utils.TransformUtils;
import com.andy.blog.common.utils.poi.ExcelUtil;
import com.andy.blog.dal.domain.SysRoleDO;
import com.andy.blog.dal.domain.SysUserDO;
import com.andy.blog.dal.domain.SysUserRoleDO;
import com.andy.blog.dal.service.SysRoleDalService;
import com.andy.blog.dal.service.SysUserDalService;
import com.andy.blog.dal.service.SysUserRoleDalService;
import com.andy.blog.dal.vo.FileInfoVO;
import com.andy.blog.dal.vo.SysRoleVO;
import com.andy.blog.dal.vo.SysUserVO;
import com.andy.blog.framework.web.service.TokenService;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.google.common.collect.Maps;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import static com.andy.blog.admin.service.impl.ArticleBusServiceImpl.USER_ARTICLE_LIKE;
import static com.andy.blog.common.utils.SecurityUtils.getLoginUser;
import static com.andy.blog.common.utils.SecurityUtils.getUserId;

/**
 * Created by andy on 2023-04-08 13:08
 */
@Service("sysUserBusService")
public class SysUserBusServiceImpl implements SysUserBusService {

    @Autowired
    private SysUserDalService userDalService;

    @Autowired
    private TokenService tokenService;

    @Autowired
    private FileBusService fileBusService;

    @Autowired
    private SysRoleDalService sysRoleDalService;

    @Resource
    private RedisCache redisCache;

    @Resource
    private SysUserRoleDalService sysUserRoleDalService;


    @Override
    public List<SysUserDTO> selectUserList(SysUserVO sysUserVO) {
        List<SysUserDO> sysUserDOS = userDalService.selectUserList(sysUserVO);
        return TransformUtils.transformList(sysUserDOS, SysUserDTO.class);
    }

    @Override
    public SysUserDO selectUserById(Long userId) {
        return userDalService.selectUserById(userId);
    }

    @Override
    public Map<String, Object> profile() {
        LoginUser loginUser = getLoginUser();
        SysUser user = loginUser.getUser();
        Map<String, Object> paramMap = Maps.newHashMap();
        paramMap.put("user", user);
        paramMap.put("roleGroup", userDalService.selectUserRoleGroup(loginUser.getUsername()));
        return paramMap;
    }

    @Override
    public void updateProfile(SysUserVO sysUserVO) {
        LoginUser loginUser = getLoginUser();
        SysUser sysUser = loginUser.getUser();
        sysUserVO.setUserName(sysUser.getUserName());

        if (StringUtils.isNotBlank(sysUserVO.getPhoneNumber()) &&
                !userDalService.checkPhoneUnique(sysUserVO.getId(), sysUserVO.getPhoneNumber())) {
            throw new BlogServiceException("修改用户[" + sysUserVO.getUserName() + "]失败，手机号码已存在");
        }
        if (StringUtils.isNotEmpty(sysUserVO.getEmail()) &&
                !userDalService.checkEmailUnique(sysUserVO.getId(), sysUserVO.getEmail())) {
            throw new BlogServiceException("修改用户[" + sysUserVO.getUserName() + "]失败，邮箱账号已存在");
        }
        sysUserVO.setId(sysUser.getId());
        sysUserVO.setPassword(null);
        sysUserVO.setAvatar(null);

        userDalService.updateUserProfile(sysUserVO);

        // 更新缓存用户信息
        sysUser.setNickName(sysUserVO.getNickName());
        sysUser.setPhoneNumber(sysUserVO.getPhoneNumber());
        sysUser.setEmail(sysUserVO.getEmail());
        sysUser.setSex(sysUserVO.getSex());
        tokenService.setLoginUser(loginUser);

        //throw new BlogServiceException("修改个人信息异常，请联系管理员");

    }

    @Override
    public void updatePwd(String oldPassword, String newPassword) {
        LoginUser loginUser = getLoginUser();
        String password = loginUser.getPassword();
        if (!SecurityUtils.matchesPassword(oldPassword, password)) {
            throw new BlogServiceException("修改密码失败，旧密码错误");
        }
        if (SecurityUtils.matchesPassword(newPassword, password)) {
            throw new BlogServiceException("新密码不能与旧密码相同");
        }
        if (userDalService.resetUserPwd(getUserId(), newPassword)) {
            // 更新缓存用户密码
            loginUser.getUser().setPassword(SecurityUtils.encryptPassword(newPassword));
            tokenService.setLoginUser(loginUser);
        } else {
            throw new BlogServiceException("修改密码异常，请联系管理员");
        }
    }

    @Override
    public Map<String, String> avatar(MultipartFile file) {
        if (Objects.isNull(file)) {
            throw new BlogServiceException(BlogResultCode.BLOG_000001, "文件不能为空");
        }

        Map<String, String> ajax = Maps.newHashMap();
        Long userId = SecurityUtils.getUserId();
        FileInfoDTO fileInfoDTO = fileBusService.uploadFile(file, new FileInfoVO());
        if (userDalService.updateUserAvatar(userId, fileInfoDTO.getFileUrl())) {
            ajax.put("imgUrl", fileInfoDTO.getFileUrl());
            // 更新缓存用户头像
            LoginUser loginUser = getLoginUser();
            loginUser.getUser().setAvatar(fileInfoDTO.getFileUrl());
            tokenService.setLoginUser(loginUser);
            return ajax;
        }

        return ajax;
    }

    @Override
    public PageUtilsDTO<SysUserDTO> selectListByPage(SysUserVO sysUserVO) {
        IPage<SysUserDO> userDOIPage = userDalService.selectListByPage(sysUserVO);
        List<SysUserDTO> userDTOS = TransformUtils.transformList(userDOIPage.getRecords(), SysUserDTO.class);
        return PageUtilsDTO.build(userDOIPage.getTotal(), userDTOS);
    }

    @Override
    public Map<String, Object> getInfo(Long userId) {
        if (!SecurityUtils.isAdmin(SecurityUtils.getUserId())) {
            List<SysUserDO> users = userDalService.selectUserList(SysUserVO.builder().id(userId).build());
            if (CollectionUtils.isEmpty(users)) {
                throw new BlogServiceException("没有权限访问用户数据！");
            }
        }

        Map<String, Object> ajax = new HashMap<>();
        List<SysRoleDO> roles = sysRoleDalService.selectRoleList(new SysRoleVO());
        ajax.put("roles", SecurityUtils.isAdmin(userId) ? roles : roles.stream().filter(r -> !SecurityUtils.isAdminByRoleId(r.getId())).collect(Collectors.toList()));
        if (Objects.nonNull(userId)) {
            SysUserDO sysUser = userDalService.selectUserById(userId);
            ajax.put("data", sysUser);
            ajax.put("roleIds", sysUser.getRoles().stream().map(SysRoleDO::getId).collect(Collectors.toList()));
        }
        return ajax;
    }

    @Override
    public SysUserDTO getUserInfo() {
        // 获取用户信息
        SysUserDO sysUserDO = userDalService.selectById(getUserId());
        Set<Object> articleLikeSet = redisCache.getSet(USER_ARTICLE_LIKE + getUserId());

        SysUserDTO sysUserDTO = TransformUtils.transform(sysUserDO, SysUserDTO.class);
        sysUserDTO.setArticleLikeSet(articleLikeSet);

        return sysUserDTO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(SysUserVO sysUserVO) {
        if (!userDalService.checkUserNameUnique(sysUserVO.getId(), sysUserVO.getUserName())) {
            throw new BlogServiceException("新增用户'" + sysUserVO.getUserName() + "'失败，登录账号已存在");
        } else if (StringUtils.isNotBlank(sysUserVO.getPhoneNumber()) && !userDalService.checkPhoneUnique(sysUserVO.getId(), sysUserVO.getPhoneNumber())) {
            throw new BlogServiceException("新增用户'" + sysUserVO.getUserName() + "'失败，手机号码已存在");
        } else if (StringUtils.isNotBlank(sysUserVO.getEmail()) && !userDalService.checkEmailUnique(sysUserVO.getId(), sysUserVO.getEmail())) {
            throw new BlogServiceException("新增用户'" + sysUserVO.getUserName() + "'失败，邮箱账号已存在");
        }

        // 新增用户信息
        long id = userDalService.insertUser(sysUserVO);

        // 新增用户与角色管理
        Long[] roleIds = sysUserVO.getRoleIds();
        if (CollectionUtils.isNotEmpty(Arrays.asList(roleIds))) {
            // 新增用户与角色管理
            List<SysUserRoleDO> list = new ArrayList<>(roleIds.length);
            for (Long roleId : roleIds) {
                SysUserRoleDO ur = new SysUserRoleDO();
                ur.setUserId(id);
                ur.setRoleId(roleId);
                list.add(ur);
            }
            sysUserRoleDalService.batchUserRole(list);
        }
    }

    @Override
    public void changeStatus(SysUserVO sysUserVO) {
        // 判断操作的是否是超级管理员
        if (Objects.nonNull(sysUserVO.getId()) && SecurityUtils.isAdmin(sysUserVO.getId())) {
            throw new BlogServiceException("不允许操作超级管理员用户");
        }

        userDalService.updateUserStatus(sysUserVO);
    }

    @Override
    public void edit(SysUserVO sysUserVO) {

        if (SecurityUtils.isAdmin(sysUserVO.getId())) {
            throw new BlogServiceException("不允许操作超级管理员用户");
        }

        if (!userDalService.checkUserNameUnique(sysUserVO.getId(), sysUserVO.getUserName())) {
            throw new BlogServiceException("登录账号已存在");
        } else if (StringUtils.isNotEmpty(sysUserVO.getPhoneNumber()) &&
                !userDalService.checkPhoneUnique(sysUserVO.getId(), sysUserVO.getPhoneNumber())) {
            throw new BlogServiceException("修改用户'" + sysUserVO.getUserName() + "'失败，手机号码已存在");
        } else if (StringUtils.isNotEmpty(sysUserVO.getEmail()) &&
                !userDalService.checkEmailUnique(sysUserVO.getId(), sysUserVO.getEmail())) {
            throw new BlogServiceException("修改用户'" + sysUserVO.getUserName() + "'失败，邮箱账号已存在");
        }

        Long userId = sysUserVO.getId();
        // 删除用户与角色关联
        sysUserRoleDalService.deleteUserRoleByUserId(userId);

        // 新增用户与角色管理
        Long[] roleIds = sysUserVO.getRoleIds();
        if (CollectionUtils.isNotEmpty(Arrays.asList(roleIds))) {
            // 新增用户与角色管理
            List<SysUserRoleDO> list = new ArrayList<>(roleIds.length);
            for (Long roleId : roleIds) {
                SysUserRoleDO ur = new SysUserRoleDO();
                ur.setUserId(userId);
                ur.setRoleId(roleId);
                list.add(ur);
            }
            sysUserRoleDalService.batchUserRole(list);
        }

        userDalService.updateUser(sysUserVO);
    }

    @Override
    public void resetPwd(SysUserVO sysUserVO) {

        if (SecurityUtils.isAdmin(sysUserVO.getId())) {
            throw new BlogServiceException("不允许操作超级管理员用户");
        }

        userDalService.resetUserPwd(sysUserVO.getId(), sysUserVO.getPassword());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void remove(Long userId) {
        if (Objects.equals(userId, getUserId())) {
            throw new BlogServiceException("当前用户不能删除");
        }

        if (SecurityUtils.isAdmin(userId)) {
            throw new BlogServiceException("不允许操作超级管理员用户");
        }

        // 删除用户与角色关联
        sysUserRoleDalService.deleteUserRoleByUserId(userId);

        userDalService.deleteUserById(userId);
    }

    @Override
    public String importUser(MultipartFile file, boolean updateSupport) throws Exception {
        ExcelUtil<SysUser> util = new ExcelUtil<>(SysUser.class);
        List<SysUser> userList = util.importExcel(file.getInputStream());
        return userDalService.importUser(userList, updateSupport, SecurityUtils.getUsername());
    }

    @Override
    public Map<String, Object> authRole(Long userId) {
        Map<String, Object> ajax = new HashMap<>();

        List<SysRoleDO> roles = sysRoleDalService.selectRolesByUserId(userId);

        List<SysRoleDO> sysRoleDOS = sysRoleDalService.selectRoleAll();

        List<SysRoleDTO> sysRoleDTOS = TransformUtils.transformList(sysRoleDOS, SysRoleDTO.class);

        for (SysRoleDTO sysRoleDTO : sysRoleDTOS) {
            for (SysRoleDO role : roles) {
                if (Objects.equals(sysRoleDTO.getId(), role.getId())) {
                    sysRoleDTO.setFlag(true);
                    break;
                }
            }
        }

        ajax.put("user", userDalService.selectUserById(userId));
        ajax.put("roles", SecurityUtils.isAdmin(userId) ? sysRoleDTOS :
                sysRoleDTOS.stream().filter(r -> !SecurityUtils.isAdminByRoleId(r.getId())).collect(Collectors.toList()));

        return ajax;
    }
}
